import { Injectable, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { UserEntity } from '../../entities/user.entity';
import { Repository } from 'typeorm';
import { RegisterUserInputDto } from '../../resolvers/dto/register.user.dto';
import { ToolService } from 'src/modules/shared/services/tool/tool.service';
import { LoginUserInputDto } from '../../resolvers/dto/login.user.dto';
import { AuthService } from 'src/modules/common/auth/auth.service';
import { LoginVo } from 'src/modules/common/auth/vo/login.vo';
import { RedisUtilsService } from 'src/modules/common/redis-utils/redis-utils.service';
import { UserTokenEntity } from '../../../entities/user_token.entity';
import  dayjs from 'dayjs'
import { InjectConfig, ConfigService } from 'nestjs-config';

@Injectable()
export class UserService {
    constructor(
        @InjectRepository(UserEntity)
        private readonly userRepository: Repository<UserEntity>,
        private readonly toolService: ToolService,
        private readonly authService: AuthService,
        private readonly redisUtilsService: RedisUtilsService,
        @InjectRepository(UserTokenEntity)
        private readonly userTokenRepository: Repository<UserTokenEntity>,
        @InjectConfig()
       private readonly configService: ConfigService,
    ){}

    async register(registerUserInputDto: RegisterUserInputDto): Promise<any>{
        const { username, password } = registerUserInputDto;
        const userInfo: UserEntity | undefined = await this.userRepository.findOne({
        where: { username },
        select: ['id'],
        });
        if (userInfo?.id) {
        throw new BadRequestException(`${username}已经存在不能重复创建`);
        }
        const user = this.userRepository.create({ username, password });
        await this.userRepository.save(user);
        return '注册成功';
    }

     async login(loginUserInputDto: LoginUserInputDto): Promise<LoginVo> {
        const { username, password } = loginUserInputDto;
        const userInfo: UserEntity | undefined = await this.userRepository.findOne({
          where: { username },
          select: ['id', 'username', 'password', 'mobile'],
        });
        await this.checkUserLock(userInfo.id);
        if (this.toolService.checkPassword(password, userInfo?.password)) {
          const { id, username, mobile } = userInfo;
            // const redisTokenKey = `blog_${id}`;
            const token: string = this.toolService.uuidToken;
            const userToken: UserTokenEntity | undefined = await this.userTokenRepository.findOne({ where: { id, platform: 'front' }, select: ['id'] });
      const tokenTable = {
        userId: id,
        token, 
        username, 
        mobile, 
        platform: 'front', 
        expireTime: dayjs().add(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
      }
            // const token: string = this.authService.generateToken({ id, username, redisTokenKey, table: 'user' });
            // this.redisUtilsService.set(redisTokenKey, { token });
            if (userToken) {
              // 可能用户修改了资料，这里就重新保存下
              await this.userTokenRepository.update(id, tokenTable);
            } else {
              const tokenSaveResult = this.userTokenRepository.create(tokenTable);
              await this.userTokenRepository.save(tokenSaveResult);
            }
            return {
              id,
              username,
              token
          };
        } else {
          await this.loginError(userInfo.id)
          throw new BadRequestException('账号或密码错误');
        }
      }
 
    async userList(): Promise<UserEntity[]>{
      return await this.userRepository.find();  
    }  

    private async loginError(userId: number): Promise<void> {
      const [redisKey, loginLockTime] = this.redisLoginLockConfig(userId);
      const redisCount = await this.redisUtilsService.get(redisKey);
      if (redisCount) {
        await this.redisUtilsService.redisClient.incr(redisKey);
      } else {
        await this.redisUtilsService.set(redisKey, 1, loginLockTime);
      }
    }

    private async checkUserLock(userId: number): Promise<void> {
      const [redisKey, loginLockTime, loginLockCount] = this.redisLoginLockConfig(userId);
      const redisCount = await this.redisUtilsService.get(redisKey);
      if (redisCount >= loginLockCount) {
        throw new BadRequestException('你输入密码错误次数太多，请30分钟后再尝试');
      }
    }


  private redisLoginLockConfig(userId: number): [string, number, number] {
    const loginLockPrefix: string = this.configService.get('redis.loginLockPrefix');
    const loginLockTime: number = this.configService.get('redis.loginLockTime');
    const redisKey: string = `${loginLockPrefix}_${userId}`;
    const loginLockCount: number = this.configService.get('redis.loginLockCount');
    return [redisKey, loginLockTime, loginLockCount];
  }
}
